<?php

/**
 * This file is part of the Framework03 PHP framework.
 * @author Walter Tamboer
 * @package Framework03
 */

class FW_Uri_Http extends FW_Uri_Abstract
{
    /**
     * @var string The URN of this URI.
     */
    private $urn;

    /**
     * @var string The username passed to this URI.
     */
    private $username = '';

    /**
     * @var string The password passed to this URI.
     */
    private $password = '';

    /**
     * @var string The host of this URI.
     */
    private $host = '';

    /**
     * @var string The port number of this URI.
     */
    private $port = 80;

    /**
     * @var string The path of this URI.
     */
    private $path = '';

    /**
     * @var string The query of this URI.
     */
    private $query = '';

    /**
     * @var string The fragment of this URI.
     */
    private $fragment = '';

    /**
     * Initializes a new instance of this class.
     * @param string $urn The unified resource name.
     */
    public function __construct($urn)
    {
        $this->urn = $urn;
        
        $pattern = '~^((//)([^/?#]*))([^?#]*)(\?([^#]*))?(#(.*))?$~';
        $status = @preg_match($pattern, $urn, $matches);

        if (!$status)
            throw new FW_Uri_Exception('Failed to parse the URN "' . $urn . '".');

        $this->path = isset($matches[4]) ? $matches[4] : $this->path;
        $this->query = isset($matches[6]) ? $matches[6] : $this->query;
        $this->fragment = isset($matches[8]) ? $matches[8] : $this->fragment;

        $combo = isset($matches[3]) ? $matches[3] : '';
        $pattern = '~^(([^:@]*)(:([^@]*))?@)?([^:]+)(:(.*))?$~';
        $status = @preg_match($pattern, $combo, $matches);

        if (!$status)
            throw new FW_Uri_Exception('Failed to parse the host "' . $combo . '".');

        $this->username = isset($matches[2]) ? $matches[2] : $this->username;
        $this->password = isset($matches[4]) ? $matches[4] : $this->password;
        $this->host = isset($matches[5]) ? $matches[5] : $this->host;
        $this->port = isset($matches[7]) ? $matches[7] : $this->port;
    }

    /**
     * Gets the username of this URI.
     * @return string
     */
    public function getUsername()
    {
        return $this->username;
    }

    /**
     * Gets the password of this URI.
     * @return string
     */
    public function getPassword()
    {
        return $this->password;
    }

    /**
     * Gets the scheme of this URI.
     * @return string
     */
    public function getScheme()
    {
        return 'http';
    }

    /**
     * Gets the host of this URI.
     * @return string
     */
    public function getHost()
    {
        return $this->host;
    }

    /**
     * Gets the port of this URI.
     * @return string
     */
    public function getPort()
    {
        return $this->port;
    }

    /**
     * Gets the path of this URI.
     * @return string
     */
    public function getPath()
    {
        return strlen($this->path) ? $this->path : '/';
    }

    /**
     * Sets the query of this URI.
     * @param string $value The new value to set.
     * @return FW_Uri_Http
     */
    public function setQuery($value)
    {
        $this->query = $value;
        return $this;
    }

    /**
     * Gets the query of this URI.
     * @return string
     */
    public function getQuery()
    {
        return $this->query;
    }

    /**
     * Gets the fragment of this URI.
     * @return string
     */
    public function getFragment()
    {
        return $this->fragment;
    }
    
    /**
     * Returns the Urn of this URI.
     * @return string
     */
    public function getUrn()
    {
        return $this->urn;
    }

    /**
     * Converts this URI to a string.
     * @return string.
     */
    public function __toString()
    {
        $result = '';

        $result .= $this->getScheme() . '://';
        $result .= $this->getHost();
        
        $port = $this->getPort();
        if ($port != 80)
            $result .= ':' . $port;
        
        $path = $this->getPath();
        if (!empty($path))
            $result .= $path;

        $query = $this->getQuery();
        if (!empty($query))
            $result .= '?' . $query;

        $fragment = $this->getFragment();
        if (!empty($fragment))
            $result .= '#' . $fragment;

        return $result;
    }
}
